// g++ x.cpp -std=c++11

#include <iostream>
#include <vector>
#include "CharTypes.h"
#include "LayoutCharacters.h"
#include "../../utils/BOOL.h"
#include "../../utils/log.h"

BOOL_ptr CharTypes::hexFlags[256] = {BOOL::FALSE};
bool CharTypes::firstIdentifierFlags[256] = {false};
BOOL_ptr CharTypes::identifierFlags[256] = {BOOL::FALSE};
bool CharTypes::whitespaceFlags[256] = {false};
std::wstring CharTypes::stringCache[256];

// http://www.codeproject.com/Articles/18314/Static-Initialization-Function-in-Classes
BOOL_ptr CharTypes::__init = CharTypes::init();
BOOL_ptr CharTypes::init()
{
  // hex
  for (short c = 0; c < 256; ++c)
  {
    // std::cout << " in hex " << c << std::endl;
    if (c >= 'A' && c <= 'F')
    {
      hexFlags[c] = BOOL::TRUE;
    }
    else if (c >= 'a' && c <= 'f')
    {
      hexFlags[c] = BOOL::TRUE;
    }
    else if (c >= '0' && c <= '9')
    {
      hexFlags[c] = BOOL::TRUE;
    }
  }
  // std::cout << "hex done" << std::endl;
  //  hex  done

  // firstidentifierflags
  for (short c = 0; c < 256; ++c)
  {
    // std::cout << "firstIdentifierFlags " << c << std::endl;
    if (c >= 'A' && c <= 'Z')
    {
      firstIdentifierFlags[c] = true;
    }
    else if (c >= 'a' && c <= 'z')
    {
      firstIdentifierFlags[c] = true;
    }
    else
    {
      firstIdentifierFlags[c] = false;
    }
  }
  firstIdentifierFlags['`'] = true;
  firstIdentifierFlags['_'] = true;
  firstIdentifierFlags['$'] = true;
  // return;

  // firstidentifierflags done

  // identifierflags
  for (short c = 0; c < 256; ++c)
  {
    if (c >= 'A' && c <= 'Z')
    {
      identifierFlags[c] = BOOL::TRUE;
    }
    else if (c >= 'a' && c <= 'z')
    {
      identifierFlags[c] = BOOL::TRUE;
    }
    else if (c >= '0' && c <= '9')
    {
      identifierFlags[c] = BOOL::TRUE;
    }
  }
  // identifierFlags['`'] = BOOL::TRUE;
  identifierFlags['_'] = BOOL::TRUE;
  identifierFlags['$'] = BOOL::TRUE;
  identifierFlags['#'] = BOOL::TRUE;
  // identifierflags  done

  // whitespaceflags
  for (int i = 0; i <= 32; ++i)
  {
    whitespaceFlags[i] = true;
  }

  whitespaceFlags[LayoutCharacters::EOI] = false;
  for (int i = 0x7F; i <= 0xA0; ++i)
  {
    whitespaceFlags[i] = true;
  }

  whitespaceFlags[160] = true; // 特别处理
  // whitespaceflags  done

  for (int i = 0; i < 256; i++)
  {
    // LOG_INFO <<"i:"<<i;
    if (identifierFlags[i])
    {
      wchar_t ch = (wchar_t)i;
      stringCache[i] = ch;
    }
  }
  return BOOL::TRUE;
}

CharTypes::CharTypes()
{
  std::cout << " in CharTypes's constructor " << std::endl;
}

CharTypes::~CharTypes()
{
  std::cout << " in CharTypes's destructor " << std::endl;
}

BOOL_ptr CharTypes::isIdentifierChar(wchar_t c)
{
  if (c <= sizeof(identifierFlags))
  {
    return identifierFlags[c];
  }
  if (c != L'　' && c != L'，' && c != L'）' && c != L'（')
  {
    return BOOL::TRUE;
  }
  else
  {
    return BOOL::FALSE;
  }
}

BOOL_ptr CharTypes::isHex(char c)
{
  if (c < 256 && hexFlags[c])
  {
    return BOOL::TRUE;
  }
  else
  {
    return BOOL::FALSE;
  }
}

BOOL_ptr CharTypes::isDigit(char c)
{

  std::cout << "in CharTypes isDigit" << std::endl;
  if (c >= '0' && c <= '9')
  {
    return BOOL::TRUE;
  }
  else
  {
    return BOOL::FALSE;
  }
}

bool CharTypes::isFirstIdentifierChar(wchar_t c)
{
  LOG_INFO << "isFirstIdentifierChar";
  LOG_INFO << "firstIdentifierFlags[" << (int)c << "]" ;
  // LOG_INFO << "sizeof(firstIdentifierFlags)[" << sizeof(firstIdentifierFlags) << "]" ;
  LOG_INFO << "firstIdentifierFlags[" << (int)c << "]:" <<  firstIdentifierFlags[(int)c];
  if ((int)c <= 256)
  {
    WLOG_INFO << "firstIdentifierFlags[" << (int)c << "]:" << firstIdentifierFlags[(int)c];
    return firstIdentifierFlags[(int)c];
  }
  
  return c != L'　' && c != L'，';
}

/**
 * @return BOOL::FALSE if {@link LayoutCharacters#EOI}
 */
bool CharTypes::isWhitespace(wchar_t c)
{
  LOG_INFO << (int)c;
  LOG_INFO << whitespaceFlags[(int)c];
  return  (
      c == L'　' // Chinese space
      ||
      c <= 256 && whitespaceFlags[(int)c]);
}

BOOL_ptr CharTypes::isWhitespace(string_ptr c)
{
  BOOL_ptr a = nullptr;
  // Chinese space
  if (c->compare("　") == 0)
  {
    return BOOL::TRUE;
  }
  else
  {
    return BOOL::FALSE;
  }
  char x = c->at(0);
  if (
      a || x <= 256 && whitespaceFlags[x])
  {
    return BOOL::TRUE;
  }
  else
  {
    return BOOL::FALSE;
  }
}

std::wstring CharTypes::valueOf(wchar_t ch)
{
  if (ch < sizeof(stringCache))
  {
    return stringCache[ch];
  }
  return L"";
}